package com.spdd.mt.common.http;

import cn.hutool.core.date.StopWatch;
import com.spdd.mt.common.util.JacksonUtils;
import lombok.Builder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;

/**
 * 自定义的拦截器
 * <p>
 * 主要打印日志
 */
@Slf4j
public class MyRequestInterceptor implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(HttpRequest httpRequest, byte[] body, ClientHttpRequestExecution clientHttpRequestExecution) throws IOException {
        // 记录请求开始时间
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 执行请求
        ClientHttpResponse response = clientHttpRequestExecution.execute(httpRequest, body);
        // 执行完毕后，这里要创建备份，要不然会报io提前关闭的异常错误
        ClientHttpResponse responseCopy = new BufferingClientHttpResponseWrapper(response);
        // 记录请求结束时间
        stopWatch.stop();
        // 获取响应内容
        StringBuilder resBody = new StringBuilder();
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(responseCopy.getBody(),
                StandardCharsets.UTF_8))) {
            String line = bufferedReader.readLine();
            while (line != null) {
                resBody.append(line);
                line = bufferedReader.readLine();
            }
        }

        // 获取请求内容
        String reqBody = "";
        // 这里可以自定义想打印什么方法或者请求的内容，如下只打印post请求的日志，因为这时候才会带上body
        if (httpRequest.getHeaders().getContentType() != null && "POST".equals(httpRequest.getMethod().name())) {
            String requestBody = new String(body, StandardCharsets.UTF_8);
            //                String contentType = httpRequest.getHeaders().getContentType().toString();
            // 这里可以对contentType做一些判断，针对其格式化请求体的内容，如"application/x-www-form-urlencoded"格式会附带一些boundary(分割线)的内容
            reqBody = requestBody;

        }

        // 打印日志的格式可以自定义
        log.info(JacksonUtils.toJson(RestLog.builder().costTime(stopWatch.getLastTaskTimeMillis()).headers(httpRequest.getHeaders()).method(httpRequest.getMethodValue())
                .reqUrl(httpRequest.getURI().toString()).reqBody(reqBody).resBody(resBody.toString()).resStatus(responseCopy.getRawStatusCode()).build()));

        return responseCopy;
    }

    /**
     * 定义日志的字段
     */
    @Data
    @Builder
    private static class RestLog {
        private String reqUrl;
        private String method;
        private HttpHeaders headers;
        private String reqBody;
        private String resBody;
        private long costTime;
        private int resStatus;
    }
}

